﻿#region Copyright
/* Product of DTL Software
 * Product Name : Support Memmory
 * Author : dinhtienlam.spkt@gmail.com
 * About: Developer of DTL Software
 * Contact : 0966 330 237
 */
#endregion

#region Using default
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Globalization; 
#endregion

namespace Lamdt.Controls.Controls
{
    public class LamdtTextBox : TextBox
    {
        public LamdtTextBox()
        {
            this.InitializeComponent();
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // LamdtTextBox
            // 
            this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.LamdtTextBox_MouseClick);
            this.Enter += new System.EventHandler(this.LamdtTextBox_Enter);
            this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.LamdtTextBox_KeyPress);
            this.ResumeLayout(false);

        }

        private TextType _typingType = TextType.None;
        [Category("LamdtAdvance")]
        public TextType TypingType
        {
            set
            {
                if (value == _typingType)
                    return;
                _typingType = value;
                switch (_typingType)
                {
                    case TextType.None:
                        this.ImeMode = ImeMode.NoControl;
                        this.TextAlign = HorizontalAlignment.Left;
                        break;
                    case TextType.Alphanumeric:
                        this.ImeMode = ImeMode.Disable;
                        this.TextAlign = HorizontalAlignment.Left;
                        break;
                    case TextType.Currency:
                        this.ImeMode = ImeMode.Disable;
                        this.TextAlign = HorizontalAlignment.Right;
                        this.ExactlyAfterDot = true;
                        break;
                    case TextType.Number:
                        this.ImeMode = ImeMode.Disable;
                        this.TextAlign = HorizontalAlignment.Right;
                        break;
                }
                this.Text = string.Empty;
            }
            get
            {
                return _typingType;
            }
        }

        [Browsable(false)]
        public string FormatNumber
        {
            get
            {
                string s = _exactlyAfterDot ? "0" : "#";
                string result = "#,0.";
                for (int i = 0; i < NumberAfterDot; i++)
                {
                    result += s;
                }
                return result;
            }
        }

        private CultureInfo _currentCulture = new CultureInfo("ja-JP");
        [Category("LamdtAdvance")]
        public string CurrentCulture
        {
            set
            {
                _currentCulture = new CultureInfo(value);
            }
            get
            {
                return _currentCulture.Name;
            }
        }

        private char DecimalChar
        {
            get
            {
                if (TypingType == TextType.Currency)
                {
                    if (string.IsNullOrEmpty(_currentCulture.NumberFormat.CurrencyDecimalSeparator))
                        return ' ';
                    return _currentCulture.NumberFormat.CurrencyDecimalSeparator[0];
                }
                else
                {
                    if (string.IsNullOrEmpty(_currentCulture.NumberFormat.NumberDecimalSeparator))
                        return ' ';
                    return _currentCulture.NumberFormat.NumberDecimalSeparator[0];
                }
            }
        }

        private char GroupChar
        {
            get
            {
                if (TypingType == TextType.Currency)
                {
                    if (string.IsNullOrEmpty(_currentCulture.NumberFormat.CurrencyGroupSeparator))
                        return ' ';
                    return _currentCulture.NumberFormat.CurrencyGroupSeparator[0];
                }
                else
                {
                    if (string.IsNullOrEmpty(_currentCulture.NumberFormat.NumberGroupSeparator))
                        return ' ';
                    return _currentCulture.NumberFormat.NumberGroupSeparator[0];
                }
            }
        }

        private bool _exactlyAfterDot = false;
        [Category("LamdtAdvance")]
        public bool ExactlyAfterDot
        {
            set
            {
                if (!value && TypingType == TextType.Currency)
                    return;
                _exactlyAfterDot = value;
            }
            get
            {
                return _exactlyAfterDot;
            }

        }

        private int _numberAfterDot = 0;
        [Category("LamdtAdvance")]
        public int NumberAfterDot
        {
            set
            {
                if (value < 0 || value > 5)
                    return;
                _numberAfterDot = value;
            }
            get
            {
                return _numberAfterDot;
            }
        }

        private bool _groupSeperating = true;
        [Category("LamdtAdvance")]
        public bool GroupSeperating
        {
            set
            {
                if (_groupSeperating == value)
                    return;
                if (value)
                    _currentCulture = new CultureInfo(CurrentCulture);
                else
                {
                    _currentCulture.NumberFormat.NumberGroupSeparator = string.Empty;
                    _currentCulture.NumberFormat.CurrencyGroupSeparator = string.Empty;
                }
                _groupSeperating = value;
            }
            get
            {
                return _groupSeperating;
            }
        }

        private decimal _value = 0;
        [Browsable(false)]
        public decimal Value
        {
            get
            {
                return _value;
            }
        }

        private string oldCorrectText = string.Empty;
        protected override void OnTextChanged(EventArgs e)
        {
            if (string.IsNullOrEmpty(this.Text))
            {
                _value = 0;
                oldCorrectText = this.Text;
                base.OnTextChanged(e);
                return;
            }
            if (this.Text.Equals(this.oldCorrectText))
            {
                base.OnTextChanged(e);
                return;
            }
            if (TypingType == TextType.Alphanumeric)
            {
                if (!this.Text.All(chr => (
                    (chr >= 'A' && chr <= 'Z') ||
                    (chr >= 'a' && chr <= 'z') ||
                    (chr >= '0' && chr <= '9')
                    )))
                {
                    this.Text = this.oldCorrectText;
                    //this.SelectionStart = this.Text.Length;
                    return;
                }
            }
            else if (TypingType == TextType.Number)
            {
                try
                {
                    if (this.Text[this.Text.Length - 1] == DecimalChar)
                    {
                        base.OnTextChanged(e);
                        return;
                    }
                    string number = this.Text.Replace(GroupChar.ToString(), "");
                    if (number.Contains(DecimalChar))
                        if (number.Length - 1 - number.IndexOf(DecimalChar) > NumberAfterDot)
                        {
                            number = number.Substring(0, number.IndexOf(DecimalChar) + 1 + NumberAfterDot);
                            this.SelectionStart = this.SelectionStart + 1;
                        }
                    int currentSelectionStart = this.Text.Length - this.SelectionStart;
                    _value = decimal.Parse(number, NumberStyles.Number, _currentCulture.NumberFormat);
                    this.Text = _value.ToString(FormatNumber, _currentCulture);
                    this.SelectionStart = this.Text.Length - currentSelectionStart;
                }
                catch (Exception)
                {
                    this.Text = this.oldCorrectText;
                }
            }
            else if (TypingType == TextType.Currency)
            {
                try
                {
                    if (this.Text[this.Text.Length - 1] == DecimalChar)
                    {
                        base.OnTextChanged(e);
                        return;
                    }
                    if (this.Text.Equals(_currentCulture.NumberFormat.CurrencySymbol) ||
                        this.Text.Equals("-" + _currentCulture.NumberFormat.CurrencySymbol) ||
                        this.Text.Equals("-"))
                        return;
                    if (this.Text.Equals("-" + _currentCulture.NumberFormat.CurrencySymbol + "0"))
                    {
                        this.SelectionStart = 2;
                        this.SelectionLength = 1;
                        return;
                    }
                    string number = this.Text.Replace(GroupChar.ToString(), "");
                    if (number.Contains(DecimalChar))
                        if (number.Length - 1 - number.IndexOf(DecimalChar) > NumberAfterDot)
                        {
                            number = number.Substring(0, number.IndexOf(DecimalChar) + 1 + NumberAfterDot);
                            this.SelectionStart = this.SelectionStart + 1;
                        }
                    int currentSelectionStart = this.Text.Length - this.SelectionStart;
                    _value = decimal.Parse(number, NumberStyles.Currency, _currentCulture.NumberFormat);
                    this.Text = _value.ToString("c" + NumberAfterDot, _currentCulture.NumberFormat);
                    this.SelectionStart = this.Text.Length - currentSelectionStart;
                }
                catch (Exception)
                {
                    this.Text = this.oldCorrectText;
                }
            }
            this.oldCorrectText = this.Text;
            base.OnTextChanged(e);
        }

        private char lastKey = '0';
        private void LamdtTextBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 8)
                return;
            if (TypingType == TextType.Alphanumeric)
            {
                if (!((e.KeyChar >= 'A' && e.KeyChar <= 'Z') ||
                    (e.KeyChar >= 'a' && e.KeyChar <= 'z') ||
                    (e.KeyChar >= '0' && e.KeyChar <= '9')))
                {
                    e.Handled = true;
                    return;
                }
                lastKey = e.KeyChar;
                return;
            }
            else if (TypingType == TextType.Number || TypingType == TextType.Currency)
            {
                if (!(e.KeyChar == '-' || e.KeyChar == DecimalChar ||
                    (e.KeyChar >= '0' && e.KeyChar <= '9')))
                {
                    e.Handled = true;
                    return;
                }
                if (e.KeyChar == '-')
                {
                    if (this.Text.Contains('-'))
                    {
                        int selectionStart = this.SelectionStart;
                        this.Text = this.Text.Remove(this.Text.IndexOf('-'), 1);
                        this.SelectionStart = selectionStart - 1;
                    }
                    else
                    {
                        int selectionStart = this.SelectionStart;
                        this.Text = '-' + this.Text;
                        this.SelectionStart = selectionStart + 1;
                    }
                    e.Handled = true;
                    return;
                }
                else if (e.KeyChar == DecimalChar)
                {
                    if (NumberAfterDot == 0 || this.Text.Contains(DecimalChar))
                    {
                        e.Handled = true;
                        if (this.Text.IndexOf(DecimalChar) == this.SelectionStart)
                            this.SelectionStart++;
                        return;
                    }
                    lastKey = e.KeyChar;
                }
            }
        }

        private void LamdtTextBox_Enter(object sender, EventArgs e)
        {
            if (_value == 0 &&
                //((this.TypingType == TextType.Number && (this.SelectionStart == 0 || this.SelectionStart == 1)) ||
                (this.TypingType == TextType.Currency && (this.SelectionStart >= 0 && this.SelectionStart <= 2))//)
                && this.SelectionLength == 0
                )
            {
                this.Text = "0";
                this.SelectionStart = this.Text.IndexOf('0') + 0;
                this.SelectionLength = 1;
            }
        }

        private void LamdtTextBox_MouseClick(object sender, MouseEventArgs e)
        {
            if (_value == 0 &&
                //((this.TypingType == TextType.Number && (this.SelectionStart == 0 || this.SelectionStart == 1)) ||
                (this.TypingType == TextType.Currency && (this.SelectionStart >= 0 && this.SelectionStart <= 2))//)
                && this.SelectionLength == 0
                )
            {
                this.Text = "0";
                this.SelectionStart = this.Text.IndexOf('0') + 0;
                this.SelectionLength = 1;
            }
        }
    }

    public enum TextType
    {
        None,
        Alphanumeric,
        Currency,
        Number
    }
}
